/********************************************
 * 系统名称: 商业汇票服务平台第4版(BBSP4)
 * 模块名称: 框架
 * 软件版权: 恒生电子股份有限公司
 * 源程序名: MathUtils.java
 * 功能说明: 
 * 开发人员: zhouwj10695
 * 开发时间: 2015年3月26日 下午5:30:28
 * 审核人员:
 * 相关文档:
 * 修改记录: 修改日期    修改人员    修改说明
 * v4.0.0.0 20150422-01 zhouwj10695 保证金冻结接口调整 M201504220051
 * v4.0.0.1 20150430-01 zhouwj10695 模拟核心记账粒度控制 M201504240024
 *******************************************/
package com.gadgets.framework.common.util;

import java.math.BigDecimal;
import java.text.DecimalFormat;

/**
 * 功能说明：数学方法
 *
 * @date 2013-8-21
 * @author Administrator
 * @email Administrator@hundsun.com
 *
 */
public class MathUtils {

	/**
	 * 获取double
	 *
	 * @param obj	Double值
	 * @return		double值
	 */
	public static double Double2double(Double obj) {
		return (obj == null) ? 0 : obj.doubleValue();
	}
	/*
	 * 默认除法运算精度
	 */
	private static final int DEFAULT_DIV_SCALE = 10;

	/**
	 * 提供精确的加法运算
	 * 
	 * @param v1 参数1
	 * @param v2 参数2
	 * @return 两个参数的和
	 */
	public static double add(double v1, double v2) {
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.add(b2).doubleValue();
	}

	/**
	 * 提供精确的加法运算
	 * 
	 * @param v1 参数1
	 * @param v2 参数2
	 * @return 两个参数的和，以字符串格式返回
	 */
	public static String add(String v1, String v2) {
		BigDecimal b1 = new BigDecimal(v1);
		BigDecimal b2 = new BigDecimal(v2);
		return b1.add(b2).toString();
	}

	/**
	 * 提供精确的减法运算
	 * 
	 * @param v1 参数1
	 * @param v2 参数2
	 * @return 两个参数的差
	 */
	public static double subtract(double v1, double v2) {
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.subtract(b2).doubleValue();
	}

	/**
	 * 提供精确的减法运算
	 * 
	 * @param v1 参数1
	 * @param v2 参数2
	 * @return 两个参数的差，以字符串格式返回
	 */
	public static String subtract(String v1, String v2) {
		BigDecimal b1 = new BigDecimal(v1);
		BigDecimal b2 = new BigDecimal(v2);
		return b1.subtract(b2).toString();
	}

	/**
	 * 提供精确的乘法运算
	 * 
	 * @param v1 参数1
	 * @param v2 参数2
	 * @return 两个参数的积
	 */
	public static double multiply(double v1, double v2) {
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.multiply(b2).doubleValue();
	}

	/**
	 * 提供精确的乘法运算
	 * 
	 * @param v1 参数1
	 * @param v2 参数2
	 * @return 两个参数的积，以字符串格式返回
	 */
	public static String multiply(String v1, String v2) {
		BigDecimal b1 = new BigDecimal(v1);
		BigDecimal b2 = new BigDecimal(v2);
		return b1.multiply(b2).toString();
	}

	/**
	 * 提供（相对）精确的除法运算，当发生除不尽的情况时，精确到小数点以后10位，以后的数字四舍五入，舍入模式采用ROUND_HALF_UP
	 * 
	 * @param v1 参数1
	 * @param v2 参数2
	 * @return 两个参数的商
	 */
	public static double divide(double v1, double v2) {
		return divide(v1, v2, DEFAULT_DIV_SCALE);
	}

	/**
	 * 提供（相对）精确的除法运算，当发生除不尽的情况时，由scale参数指定精度，以后的数字四舍五入，舍入模式采用ROUND_HALF_UP
	 * 
	 * @param v1 参数1
	 * @param v2 参数2
	 * @param scale 小数点后保留几位
	 * @return 两个参数的商
	 */
	public static double divide(double v1, double v2, int scale) {
		return divide(v1, v2, scale, BigDecimal.ROUND_HALF_UP);
	}

	/**
	 * 提供（相对）精确的除法运算，当发生除不尽的情况时，由scale参数指定精度，以后的数字四舍五入，舍入模式采用用户指定舍入模式
	 * 
	 * @param v1 参数1
	 * @param v2 参数2
	 * @param scale 小数点后保留几位
	 * @param round_mode 指定的舍入模式
	 * @return 两个参数的商
	 */
	public static double divide(double v1, double v2, int scale, int round_mode) {
		if (scale < 0) {
			throw new IllegalArgumentException(
					"The scale must be a positive integer or zero");
		}
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.divide(b2, scale, round_mode).doubleValue();
	}

	/**
	 * 提供（相对）精确的除法运算，当发生除不尽的情况时，精确到小数点以后10位，以后的数字四舍五入，舍入模式采用ROUND_HALF_UP
	 * 
	 * @param v1 参数1
	 * @param v2 参数2
	 * @return 两个参数的商，以字符串格式返回
	 */
	public static String divide(String v1, String v2) {
		return divide(v1, v2, DEFAULT_DIV_SCALE);
	}

	/**
	 * 提供（相对）精确的除法运算，当发生除不尽的情况时，由scale参数指定精度，以后的数字四舍五入，舍入模式采用ROUND_HALF_UP
	 * 
	 * @param v1 参数1
	 * @param v2 参数2
	 * @param scale 小数点后保留几位
	 * @return 两个参数的商，以字符串格式返回
	 */
	public static String divide(String v1, String v2, int scale) {
		return divide(v1, v2, scale, BigDecimal.ROUND_HALF_UP);
	}

	/**
	 * 提供（相对）精确的除法运算，当发生除不尽的情况时，由scale参数指定精度，以后的数字四舍五入，舍入模式采用用户指定舍入模式
	 * 
	 * @param v1 参数1
	 * @param v2 参数2
	 * @param scale 小数点后保留几位
	 * @param round_mode 指定的舍入模式
	 * @return 两个参数的商，以字符串格式返回
	 */
	public static String divide(String v1, String v2, int scale, int round_mode) {
		if (scale < 0) {
			throw new IllegalArgumentException(
					"The scale must be a positive integer or zero");
		}
		BigDecimal b1 = new BigDecimal(v1);
		BigDecimal b2 = new BigDecimal(v2);
		return b1.divide(b2, scale, round_mode).toString();
	}

	/**
	 * 提供精确的小数位四舍五入处理，舍入模式采用ROUND_HALF_UP
	 * 
	 * @param v 需要四舍五入的数字
	 * @param scale 小数点后保留几位
	 * @return 四舍五入后的结果
	 */
	public static double round(double v, int scale) {
		return round(v, scale, BigDecimal.ROUND_HALF_UP);
	}

	/**
	 * 提供精确的小数位四舍五入处理，舍入模式采用用户指定舍入模式
	 * 
	 * @param v 需要四舍五入的数字
	 * @param scale 小数点后保留几位
	 * @param round_mode 指定的舍入模式
	 * @return 四舍五入后的结果
	 */
	public static double round(double v, int scale, int round_mode) {
		if (scale < 0) {
			throw new IllegalArgumentException(
					"The scale must be a positive integer or zero");
		}
		BigDecimal b = new BigDecimal(Double.toString(v));
		return b.setScale(scale, round_mode).doubleValue();
	}

	/**
	 * 提供精确的小数位四舍五入处理，舍入模式采用ROUND_HALF_UP
	 * 
	 * @param v 需要四舍五入的数字
	 * @param scale 小数点后保留几位
	 * @return 四舍五入后的结果，以字符串格式返回
	 */
	public static String round(String v, int scale) {
		return round(v, scale, BigDecimal.ROUND_HALF_UP);
	}

	/**
	 * 提供精确的小数位四舍五入处理，舍入模式采用用户指定舍入模式
	 * 
	 * @param v 需要四舍五入的数字
	 * @param scale 小数点后保留几位
	 * @param round_mode 指定的舍入模式
	 * @return 四舍五入后的结果，以字符串格式返回
	 */
	public static String round(String v, int scale, int round_mode) {
		if (v == null) {
			return null;
		}

		if (scale < 0) {
			throw new IllegalArgumentException(
					"The scale must be a positive integer or zero");
		}
		BigDecimal b = new BigDecimal(v);
		return b.setScale(scale, round_mode).toString();
	}
	
	/**
	 * 提供精确的小数位四舍五入处理，舍入模式采用ROUND_HALF_UP
	 * 
	 * @param v 需要四舍五入的数字
	 * @param scale 小数点后保留几位
	 * @return 四舍五入后的结果，以Double格式返回
	 */
	public static Double round(Double v, int scale) {
		return round(v, scale, BigDecimal.ROUND_HALF_UP);
	}

	/**
	 * 提供精确的小数位四舍五入处理，舍入模式采用用户指定舍入模式
	 * 
	 * @param v 需要四舍五入的数字
	 * @param scale 小数点后保留几位
	 * @param round_mode 指定的舍入模式
	 * @return 四舍五入后的结果，以Double格式返回
	 */
	public static Double round(Double v, int scale, int round_mode) {
		if (v == null) {
			return null;
		}

		return new Double(round(v.doubleValue(), scale, round_mode));
	}
	
	/**
	 * 
	 * 双精度数格式化（保留四位小数）
	 *
	 * @param d	双精度数
	 * @return	双精度数
	 */
	public static double format4bit(double d){
		d = d + 0.00000001;
        DecimalFormat df = new DecimalFormat("##0.0000");
		String str = df.format(d);
		if (str.equals("0.00")) {
			str = "0";
		}
		return Double.parseDouble(str);
	}
	
	/**
	 * DOUBLE转换double双精度数格式化（保留四位小数）
	 *
	 * @param obj	
	 * @return
	 */
	public static double Double2doubleFormat4bit(Double obj) {
		double d = (obj == null) ? 0 : obj.doubleValue();
		d = d + 0.00000001;
		DecimalFormat df = new DecimalFormat("##0.0000");
		String str = df.format(d);
		if (str.equals("0.00")) {
			str = "0";
		}
		return Double.parseDouble(str);
	}
	
	/**
	 * 
	 * 双精度数格式化（保留两位小数）
	 *
	 * @param d	双精度数
	 * @return	双精度数(String类型)
	 */
	public static String formatnodot(double d){
		d = d + 0.00000001;
        DecimalFormat df = new DecimalFormat("##0.00");
		String str = df.format(d);
		if (str.equals("0.00")) {
			str = "0";
		}
		return str;
	}
	
	/**
	 * 
	 * 双精度数格式化（保留两位小数）
	 *
	 * @param d 双精度数
	 * @return  双精度数(double类型)
	 */
	public static double format2bit(double d){
		d = d + 0.00000001;
        DecimalFormat df = new DecimalFormat("##0.00");
		String str = df.format(d);
		if (str.equals("0.00")) {
			str = "0";
		}
		return Double.parseDouble(str);
	}
	
	/**
	 * 
	 * 格式化金额，返回结果，如123,456.78
	 *
	 * @param d
	 * @return
	 */
	public static String formatMoney(BigDecimal d){
        DecimalFormat df = new DecimalFormat("#,##0.00");
		String str = df.format(d);
		return str;
	}
	//20150722-01 chenlk14174 支持打印修改日期格式  金额格式化 M201507210337 beg 				
	
	/**
	 * 
	 *格式化金额，返回结果，如123,456.78
	 *
	 * @param d	双精度数
	 * @return	双精度数(String类型)
	 */
	public static String formatDoubleMoney(double d){
		d = d + 0.00000001;
        DecimalFormat df = new DecimalFormat("#,##0.00");
		String str = df.format(d);
		if (str.equals("0.00")) {
			str = "0";
		}
		return str;
	}
	//20150722-01 chenlk14174 支持打印修改日期格式 金额格式化  M201507210337 END 				
//20160127 -chenlk14174 	M201601230009 厦门国际
	/**
	 * 
	 *格式化金额，返回结果，如123,456.78
	 *0金额返回0.00
	 *
	 * @param d	双精度数
	 * @return	双精度数(String类型)
	 */
	public static String formatDoubleMoneyReturn(double d){
		d = d + 0.00000001;
		DecimalFormat df = new DecimalFormat("#,##0.00");
		String str = df.format(d);
		return str;
	}
		
	/**
	 * 
	 * 格式化成年利率
	 *
	 * @param rate 利率  例如5.34(百分号)或者5.23(千分号)
	 * @param rateType 利率类型
	 * @return
	 */
	public static double tranToYearRate(double rate, String rateType){
		double yearRate = 0d;
		if("1".equals(rateType)){
			yearRate = multiply(rate, 3.6d);
		}else if("30".equals(rateType)){
			yearRate = multiply(rate, 1.2d);
		}else if("360".equals(rateType)){
			yearRate = rate;
		}
		
		return yearRate;
	}
	
	/**
	 * 
	 * 格式化成人行发送报文的利率格式，统一为年利率
	 * PercentageRate(7位数字，小数部分6位)
	 * 5.34(百分号)转换为0.053400，5.23(千分号)转换为0.062760
	 * 
	 * @param rate 利率  例如5.34(百分号)或者5.23(千分号)
	 * @param rateType 利率类型
	 * @return PercentageRate(7位数字，小数部分6位)
	 */
	public static String tranToDraftRate(double rate, String rateType){
		double yearRate = 0d;
		if("1".equals(rateType)){
			yearRate = multiply(rate, 3.6d);
		}else if("30".equals(rateType)){
			yearRate = multiply(rate, 1.2d);
		}else if("360".equals(rateType)){
			yearRate = rate;
		}
		double draftYearRate = divide(yearRate, 100);
		
		DecimalFormat decimalFormat = new DecimalFormat("#0.000000");
		return decimalFormat.format(draftYearRate);
	}

	/**
	 * 格式化利率为6位小数
	 *
	 * @param rate
	 * @return
	 */
	public static String tranToRateStr(Double rate) {
		DecimalFormat decimalFormat = new DecimalFormat("#0.0000");
		return decimalFormat.format(rate);
	}
	/**
	 * 
	 * 判断一个整数的奇偶性
	 *
	 * @param num  待判断的整数
	 * @return 0-偶数     1-奇数
	 */
	public static int  judgeOddEven(int num){
		if(num%2==0){
			return 0;
		}else{
			return 1;
		}
	}
	
	/**
	 * 将金额字符串格式化成Double,如"*1,234,567.89"转换成"1234567.89"
	 * @param money
	 * @param token
	 * @return
	 */
	public static double formatMoneyToDouble(String money, String token) {
		String reg = "[" + token + "]";
		return Double.parseDouble(money.replaceAll(reg, ""));
	}
	
	/**
	 * 将金额字符串格式化成String,如"*1,234,567.89"转换成"1234567.89"
	 * @param money
	 * @param token
	 * @return
	 */
	public static String formatMoneyToNormal(String money, String token) {
		String reg = "[" + token + "]";
		return money.replaceAll(reg, "");
	}
	
	//20140928-01-zhoujl08981   提供三个double类型的精确加法
	/**
	 * 
	 * 提供精确的加法
	 *
	 * @param v1
	 * @param v2
	 * @param v2
	 * @return
	 */
	public static double add(double v1, double v2, double v3) {
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		BigDecimal b3 = new BigDecimal(Double.toString(v3));
		return b1.add(b2).add(b3).doubleValue();
	}
	
	// 20150213-01 zhouwj10695 提供n个double类型的精确加法 beg
	/**
	 * 功能说明: n个double类型的精确加法
	 *
	 * @param v1
	 * @param vn
	 * @return
	 */
	public static double add(double v1, double... vn) {
		int count = 0;
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		do {
			if (0 == vn.length) {
				break;
			}
			BigDecimal bn = new BigDecimal(Double.toString(vn[(count++)]));
			b1 = b1.add(bn);
			if (count == vn.length) {
				break;
			}
		} while (true );
		return b1.doubleValue();
	}

	/**
	 * 两个double类型相加
	 * @param v1
	 * @param v2
	 * @param scale 精度
	 * @return
	 */
	public static double add(double v1, double v2, int scale) {
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.add(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
	}
	
	/**
	 * 功能说明: n个double类型的精确加法
	 *
	 * @param v1
	 * @param vn
	 * @return
	 */
	public static double add(String v1, String... vn) {
		int count = 0;
		BigDecimal b1 = new BigDecimal(v1);
		while(true) {
			if (0 == vn.length) {
				break;
			}
			BigDecimal bn = new BigDecimal(vn[(count++)]);
			b1 = b1.add(bn);
			if (count == vn.length) {
				break;
			}
		}
		return b1.doubleValue();
	}
	// 20150213-01 zhouwj10695 提供n个double类型的精确加法 end
	
	// v4.0.0.1 20150430-01 zhouwj10695 模拟核心记账粒度控制 M201504240024 beg
	/**
	 * 两个double类型比较大小
	 *
	 * @param v1
	 * @param v2
	 * @return
	 */
	public static int compare(double v1, double v2) {
		BigDecimal b1 = new BigDecimal(v1);
		BigDecimal b2 = new BigDecimal(v2);
		return b1.compareTo(b2);
	}
	// v4.0.0.1 20150430-01 zhouwj10695 模拟核心记账粒度控制 M201504240024 end

	/**
	 * 两个double类型比较大小 如果2个数相减结果误差在0.005以内认为是无误差
	 *
	 * @param v1
	 * @param v2
	 * @return boolean
	 */
	public static boolean compareMoney(double v1, double v2) {
		return (Math.abs(v1-v2) <= 0.005) ? true : false;
	}

}
